/*!
\copyright  Copyright (c) 2024 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file       streaming_statistics_utils.c
*/

#include "streaming_statistics_utils.h"
#include "av_seids.h"
#include "handset_service.h"
#include "le_unicast_manager.h"
#include "mirror_profile.h"
#include "peer_signalling.h"
#include "vm.h"
#include <logging.h>
#include "audio_info.h"
#include "audio_sources.h"
#include "device_properties.h"
#include "mirror_profile.h"
#include "bt_device.h"

#define STREAMING_IS_LOSSLESS_INDICATOR 0xaf

bool StreamingStatistics_GetCisRssi(int16_t *rssi)
{
    *rssi = 0;
#ifdef INCLUDE_LE_AUDIO_UNICAST
    DEBUG_LOG_VERBOSE("streamingStatistics_GetCisRssi");
    tp_bdaddr addr = {0};
    hci_connection_handle_t conn_handle = {LE_INVALID_CIS_HANDLE};
#ifdef ENABLE_LEA_CIS_DELEGATION
    MirrorProfile_GetCisHandle(&conn_handle, NULL, NULL, NULL);
#else
    LeUnicastManager_GetCisHandles(1, &conn_handle);
#endif

    if(conn_handle == LE_INVALID_CIS_HANDLE)
    {
        DEBUG_LOG_VERBOSE("streamingStatistics_GetCisRssi Couldn't get CIS handle.");
        return FALSE;
    }
    /* Ensure to get the device address associated to the routed source */
    generic_source_t source = AudioInfo_GetRoutedGenericSource();
    PanicFalse(GenericSource_IsValid(source));
    PanicFalse(GenericSource_IsAudio(source));
    if (StreamingStatistics_GetTpAddressFromAudioSource(source.u.audio, &addr))
    {
        if (!VmCisConnGetRssi(&addr, conn_handle, (int16 *)rssi))
        {
            DEBUG_LOG_VERBOSE("streamingStatistics_GetCisRssi Couldn't get RSSI.");
            return FALSE;
        }
        DEBUG_LOG_VERBOSE("streamingStatistics_GetCisRssi rssi 0x%x", *rssi);
        return TRUE;
    }
    DEBUG_LOG_VERBOSE("streamingStatistics_GetCisRssi Couldn't get handset tpaddr.");
#endif /* INCLUDE_LE_UNICAST */
    return FALSE;
}

bool StreamingStatistics_CalculateBitrate(const vm_transform_query_bitrate_t prev_bitrate_info,
                                          const vm_transform_query_bitrate_t new_bitrate_info,
                                          uint32_t *bitrate)
{

    DEBUG_LOG_VERBOSE("streamingStatistics_GetBitRate prev: time: 0x%x, bytes: 0x%x - new: time: 0x%x, bytes:0x%x", prev_bitrate_info.timestamp, prev_bitrate_info.bytes_processed, new_bitrate_info.timestamp, new_bitrate_info.bytes_processed);
    if ((prev_bitrate_info.timestamp == 0) ||
        (prev_bitrate_info.timestamp > new_bitrate_info.timestamp) ||
        (prev_bitrate_info.bytes_processed > new_bitrate_info.bytes_processed) ||
        (prev_bitrate_info.packets_processed > new_bitrate_info.packets_processed))
    {
        /* No previous report or something has wrapped around */
        DEBUG_LOG_VERBOSE("streamingStatistics_GetBitRate Return 0 Validation error");
        return FALSE;
    }

    uint32_t microseconds = new_bitrate_info.timestamp - prev_bitrate_info.timestamp;
    uint32_t bytes = new_bitrate_info.bytes_processed - prev_bitrate_info.bytes_processed;
    uint32_t packets = new_bitrate_info.packets_processed - prev_bitrate_info.packets_processed;

    uint32_t headerSize = packets * STREAMING_RTP_HEADER_SIZE;

    if (headerSize > bytes)
    {
        DEBUG_LOG_VERBOSE("streamingStatistics_GetBitRate Return 0 header > bytes");
        return FALSE;
    }

    uint32_t audioBytes = bytes - headerSize;
    uint64_t bytesPerSec = ((uint64_t)audioBytes * (uint64_t)STREAMING_MICROSECONDS_IN_SECOND) / (uint64_t)microseconds;
    uint64_t bitsPerSec = bytesPerSec * 8;

    if (bitsPerSec > UINT32_MAX)
    {
        DEBUG_LOG_VERBOSE("streamingStatistics_GetBitRate Return 0 bitsPerSec too big");
        return FALSE;
    }

    *bitrate = (uint32_t)bitsPerSec;

    return TRUE;
}

bool StreamingStatistics_HasLosslessIndicator(uint32_t ssrc)
{
    return (ssrc & 0xFF) == STREAMING_IS_LOSSLESS_INDICATOR;
}

bool StreamingStatistics_IsA2dpAdaptive(uint8_t seid)
{
    return seid == AV_SEID_APTX_ADAPTIVE_SNK || seid == AV_SEID_APTX_ADAPTIVE_TWS_SNK;
}

uint16_t StreamingStatistics_GetBitrateFactor(void)
{
    // Double bitrate to account for peer.
    return appPeerSigIsConnected() ? 2 * KBIT_IN_MBIT : KBIT_IN_MBIT;
}

bool StreamingStatistics_GetTpAddressFromAudioSource(audio_source_t audio_source, tp_bdaddr *tpaddr)
{
    device_t device = NULL;
    
#if defined(INCLUDE_MIRRORING)
    /* Secondary can only get the device through the mirror profile */
    if(!BtDevice_IsMyAddressPrimary())
    {
        bdaddr *mirror_addr = NULL;
        
        if (AudioSource_IsA2dp(audio_source))
        {
            mirror_addr = MirrorProfile_GetMirroredDeviceAddress();
        }
#ifdef ENABLE_LEA_CIS_DELEGATION  
        else if (AudioSource_IsLeAudio(audio_source))
        {
            mirror_addr = MirrorProfile_GetCisMirroredDeviceAddress();
        }
#endif
        if(mirror_addr)
        {
            device = BtDevice_GetDeviceForBdAddr(mirror_addr);
        }
    }
    else
#endif
    {
        device = AudioSources_GetAudioSourceDevice(audio_source);
    }

    if (device && DeviceProperties_GetTpBdaddr(device, tpaddr))
    {
        return TRUE;
    }

    return FALSE;
}
